/**
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2008，所有权利保留。
 * 
 * 项目名：	rumba
 * 文件名：	RPCMutex.java
 * 模块说明：	
 * 修改历史：
 * Feb 5, 2008 - lxm - 创建。
 */
package com.hd123.rumba.gwt.base.client.util;

import java.util.Date;
import java.util.HashSet;

import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.hd123.rumba.gwt.base.client.exception.ClientBizException;

/**
 * 互斥信号量
 * 
 * @author lxm
 * 
 */
public class Mutex {

  /** @see #waitFor(String, int, Callback) */
  public static void waitFor(String mutexId, Callback callback) throws ClientBizException {
    waitFor(mutexId, 0, callback);
  }

  /**
   * 等待指定的互斥信号量。
   * 
   * @param mutexId
   *            指定互斥信号量的唯一标识。
   * @param timeout
   *            指定等待超时时间，单位毫秒。默认情况下取值为0，即不等待。
   * @param callback
   *            指定等待返回时被调用，包含有回调的类。不可为null。
   * @throws ClientBizException
   */
  public static void waitFor(String mutexId, int timeout, Callback callback)
      throws ClientBizException {
    ObjectUtil.checkParameterNotNull(callback, "callback");
    if (isFree(mutexId)) {
      mutexSet.add(mutexId);
      callback.onSuccess();
    } else if (timeout <= 0) {
      callback.onFailure(ClientBizException.rpcTimeout(mutexId));
    } else {
      MutexTimer timer = new MutexTimer(mutexId, timeout, callback);
      timer.schedule(10);
    }
  }

  /**
   * 释放指定的互斥信号量。
   * 
   * @param mutexId
   *            指定互斥信号量的唯一标识。
   */
  public static void release(String mutexId) {
    mutexSet.remove(mutexId);
  }

  /**
   * 返回指定信号量的状态是否已被释放。
   * 
   * @param mutextId
   *            指定互斥信号量的唯一标识。
   * @return
   */
  public static boolean isFree(String mutextId) {
    return !mutexSet.contains(mutextId);
  }

  /**
   * 互斥信号量回调函数类
   * 
   * @author lxm
   * 
   */
  public static abstract class Callback {

    public void onFailure(ClientBizException e) {
      Window.alert(e.getMessage());
    };

    public abstract void onSuccess();
  }

  private static class MutexTimer extends Timer {

    public MutexTimer(String mutexId, int timeout, Callback callback) {
      super();
      assert callback != null;
      this.mutexId = mutexId;
      this.timeout = timeout;
      this.callback = callback;
    }

    private String mutexId;
    private int timeout;
    private Callback callback;
    private long startTime = -1;

    public void run() {
      if (Mutex.isFree(mutexId)) {
        this.cancel();
        Mutex.mutexSet.add(mutexId);
        callback.onSuccess();
      } else {
        if (startTime < 0)
          startTime = (new Date()).getTime();
        if ((new Date()).getTime() - startTime >= timeout) {
          this.cancel();
          callback.onFailure(ClientBizException.rpcTimeout(mutexId));
        }
      }
    }

  }

  /** 互斥信号量列表 */
  private static HashSet mutexSet = new HashSet();
}
